using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Xml.Linq;

namespace WB.Mvc.Forms.Widgets
{
	/// <summary>
	/// A widget is a representation of an HTML input element.
	/// The widget handles the rendering of the HTML, and the extraction of data from
	/// a GET/POST dictionary that corresponds to the widget.
	/// </summary>
	public abstract class Widget
	{
		private readonly IDictionary<string, object> attributes;

		/// <summary>
		/// Creates an instance of <see cref="Widget"/>.
		/// </summary>
		protected Widget(string name) : this(name, new Dictionary<string, object>())
		{
		}

		/// <summary>
		/// Creates an instance of <see cref="Widget"/>.
		/// </summary>
		/// <param name="name">Name for the id and name attributes of the widget's output.</param>
		/// <param name="attributes">Attributes for the widget's output.</param>
		protected Widget(string name, IDictionary<string, object> attributes)
		{
			if (String.IsNullOrEmpty(name))
				throw new ArgumentException("Can not be null or empty", name);
			this.attributes = attributes;

			if (!this.attributes.ContainsKey("name"))
				this.attributes["name"] = name;
			if (!this.attributes.ContainsKey("id"))
				this.attributes["id"] = name;
		}

		public virtual IDictionary<string, object> Attributes
		{
			get { return attributes; }
		}

		/// <summary>
		/// Name for the id and name attributes of the widget's output.
		/// </summary>
		public virtual string Name
		{
			get { return Attributes["name"].ToString(); }
			set
			{
				if (String.IsNullOrEmpty(value))
					throw new InvalidOperationException("Name can not be null or empty.");
				Attributes["name"] = value;
			}
		}

		/// <summary>
		/// Value of the widget's input.  Defaults to empty string.
		/// </summary>
		[DefaultValue("")]
		public virtual object Value
		{
			get
			{
				if (attributes.ContainsKey("value"))
					return attributes["value"];
				return string.Empty;
			}
			set { attributes["value"] = value; }
		}

		public static implicit operator XElement(Widget widget)
		{
			return XElement.Parse(widget.ToHtml());
		}

		/// <summary>
		/// Returns the HTML string that corresponds to the widget.
		/// </summary>
		public abstract string ToHtml();
	}
}